<?php
/**
 * Cache
 */

class Cache {

	/// 项目，如果h
	protected $app;

	/// 标记是否是外网IP访问
	protected $remote;

	protected $conf_name;

    /**
     * 构造函数
     *
     * @access public
     */
    public function __construct($app='', $remote=false) {

    	if (empty($app)) {
    		trigger_error(__FUNCTION__.': 没有指定app！', E_USER_ERROR);
    	}

    	$this->app = $app;

    	$this->remote = $remote;

    	$this->set_conf_name();
    }

    /**
     * 得到一个缓存值
     *
     * @param string key
     * @param string cache_class 缓存分类名
     * @param boolean retry, 是否要支持故障转移，默认是支持的
     */
    public function get($cache_class, $key, $retry=1) {

    	list($plugin_class, $server_list, $timeout, $version) = $this->check_cache_class($cache_class);

    	$tmp = $this->get_first($server_list);
    	if ($tmp['off']) return false;

    	$cache = get_instance_of($plugin_class, 'connect', array($server_list));

    	/// key
    	$key = $this->get_key($key, $cache_class, $version);
    	C('_ck', $key);

    	$this->Q(1);

    	$ret = $cache->get($server_list, $key, $retry);

    	return $this->simple_get($ret, $key, $cache_class, $version);
    }

    /**
     * 设置一个缓存
     *
     * @param string key
     * @param string value
     * @param string cache_class 缓存分类名
     * @param boolean retry, 是否要支持故障转移，默认是支持的
     */
    public function set($cache_class, $key, $value, $retry=1) {

    	list($plugin_class, $server_list, $timeout, $version) = $this->check_cache_class($cache_class);

    	$tmp = $this->get_first($server_list);
    	if ($tmp['off']) return false;

    	$cache = get_instance_of($plugin_class, 'connect', array($server_list));

    	/// key
    	$key = $this->get_key($key, $cache_class, $version);
    	C('_ck', $key);

    	$this->W(1);

    	return $cache->set($this->app, $cache_class, $this->remote, $server_list, $key, $value, $timeout, $retry, $version);
    }

    /**
     * 删除一个缓存
     *
     * @param string key
     * @param string cache_class 缓存分类名
     * @param boolean retry, 是否要支持故障转移，默认是不支持的，因为没必要
     */
    public function delete($cache_class, $key, $retry=0) {

    	list($plugin_class, $server_list, $timeout, $version) = $this->check_cache_class($cache_class);

    	$tmp = $this->get_first($server_list);
    	if ($tmp['off']) return false;

    	$cache = get_instance_of($plugin_class, 'connect', array($server_list));

    	/// key
    	$key = $this->get_key($key, $cache_class, $version);
    	C('_ck', $key);

    	return $cache->delete($this->app, $cache_class, $this->remote, $server_list, $key, $retry, $version);
    }

    /**
     * 清空缓存
     *
     * 本函数对于memcache、tt，不会削去使用的内存空间
     *
     * 不推荐使用，如果需要使用，请使用后台缓存管理
     *
     * 会清除cache_class所在缓存服务器的所有缓存，慎重！慎重！慎重！
     *
     * @param string cache_class 缓存分类名
     * @param boolean retry, 是否要支持故障转移，默认是不支持的，因为没必要
     */
    public function clear($cache_class='', $retry=0) {

    	list($plugin_class, $server_list, $timeout, $version) = $this->check_cache_class($cache_class);

    	$tmp = $this->get_first($server_list);
    	if ($tmp['off']) return false;

    	$cache = get_instance_of($plugin_class, 'connect', array($server_list));

    	return $cache->clear($server_list, $retry);
    }

    /**
     * 读取缓存次数
     */
    public function Q($count='') {
    	static $_times = 0;
    	if (empty($count)) return $_times;
    	else $_times++;
    }

    /**
     * 写入缓存次数
     */
    public function W($count='') {
    	static $_times = 0;
    	if (empty($count)) return $_times;
    	else $_times++;
    }

    /**
     * 设置项目
     *
     * @param string $app
     */
    public function set_app($app) {
    	$this->app = $app;
    	$this->set_conf_name();
    }

    /**
     * 获得当前项目
     *
     * @return string
     */
    public function get_app() {
    	return $this->app;
    }

    /**
     * 设置conf_name
     */
    private function set_conf_name() {
    	//$this->conf_name = strtoupper('cache_'.$this->app);
    	$this->conf_name = 'CACHE_W';
    }

    /**
     * 得到key
     */
    private function get_key($key, $cache_class, $version)
    {
    	if (strlen($version) > 0) {
    		$cache_class .= '-'.$version;
    	}

    	if (is_array($key)) {
    		$ret = array();
    		foreach ($key as $k=>$v) {
    			$ret[] = $this->app.'-'.$cache_class.'-'.$v;
    		}
    		return $ret;
    	} else {
    		return $this->app.'-'.$cache_class.'-'.$key;
    	}
    }

    /**
     * 多key取值时，最后get，返回结果key简化掉前缀 app,cache_class,version
     */
    private function simple_get($res, $key, $cache_class, $version) {

    	if (strlen($version) > 0) {
    		$cache_class .= '-'.$version;
    	}

    	if (is_array($key)) {
    		$ret = array();
    		$prefix = $this->app.'-'.$cache_class.'-';
    		foreach ($res as $k=>$v) {
    			$k = str_replace('*&#^$#*=='.$prefix, '', '*&#^$#*=='.$k); /// ''*&#^$#*=='.'防止$k中有多个跟prefix一样的字串
    			$ret[$k] = $v;
    		}

    		$ret2 = array();
    		foreach ($key as $k=>$v) {

    			$v = str_replace('*&#^$#*=='.$prefix, '', '*&#^$#*=='.$v); /// ''*&#^$#*=='.'防止$v中有多个跟prefix一样的字串

    			if (isset($ret[$v])) $ret2[$v] = $ret[$v];
    			else {
    				$ret2[$v] = false;
    			}
    		}
    		return $ret2;
    	}
    	else return $res;
    }

    /**
     * 检查缓存分类名cache_class的合法性
     *
     * @param string cache_class
     *
     * @return array array(cache信息，server信息)
     */
    private function check_cache_class($cache_class='') {

    	$remote = $this->remote;

    	/// 如果出错，直接强制退出
    	if (empty($cache_class)) {
    		trigger_error(__FUNCTION__.': 缓存类型不能为空', E_USER_ERROR);
    	}

    	/// 如果$cache_class不存在，或者$cache_class没有对应的server信息，强制退出
    	$conf = C($this->conf_name);

    	if (!isset($conf['cache_list'][$cache_class])) {
    		trigger_error(__FUNCTION__.': 缓存类型['.$cache_class.']在配置文件里没有定义', E_USER_ERROR);
    	}

    	$server_ids = $conf['cache_list'][$cache_class]['server_id'];

    	$plugin_class = '';
    	$version = '';
    	$timeout = 0;
    	$server_list = array();
    	$tmp_type = array();
    	foreach ($server_ids as $key=>$server_id) {
    		if (!isset($conf['server_list'][$server_id])) {
    			trigger_error(__FUNCTION__.': 缓存类型['.$cache_class.']定义的server ['.$server_id.'] 在server_list里没有定义', E_USER_ERROR);
    		}
    		else {

    			if (isset($conf['cache_list'][$cache_class]['version'])) {
    				$version = $conf['cache_list'][$cache_class]['version'];
    			}
    			$conf['server_list'][$server_id]['timeout'] = $conf['cache_list'][$cache_class]['timeout'];
    			$conf['server_list'][$server_id]['off'] = (isset($conf['cache_list'][$cache_class]['off']) && $conf['cache_list'][$cache_class]['off']) ? true : false;
    			$timeout = $conf['cache_list'][$cache_class]['timeout'];

    			$plugin_class = parse_name('cache_'.$conf['server_list'][$server_id]['type'], 1);
    			$tmp_type[$conf['server_list'][$server_id]['type']] = 1;

    			$server_list[$server_id] = $conf['server_list'][$server_id];
    		}
    	}

    	/// 判断，如果一组plugin里使用了两种不同的cache server，die!
    	if (count($tmp_type) > 1) {
    		trigger_error(__FUNCTION__.': 缓存类型['.$cache_class.']在定义的cache server类型超过1种', E_USER_ERROR);
    	}

    	/// 根据是否是远程访问，封装server_list
//    	foreach ($server_list as $k=>$server) {
//
//    		if ($remote && isset($server['remote_host'])) {
//    			$server['host'] = $server['remote_host'];
//    		}
//    		unset($server['remote_host']);
//
//    		$server_list[$k] = $server;
//    	}

    	return array($plugin_class, $server_list, $timeout, $version);

    }

    private function get_first($ary) {

    	if (!is_array($ary)) {
    		trigger_error(__FUNCTION__.': 参数必须是数组', E_USER_ERROR);
    	}

    	if (count($ary) < 1) return false;

    	return array_shift($ary);
    }
}
?>